#include "stdio.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_i2c.h"
#include "oledfont.h"
#include "iot_gpio.h"


#define OLED_TASK_STACK_SIZE 4096
#define OLED_TASK_PRIO 25    

#define OLED_CMD  0	 //写命令
#define OLED_DATA 1	 //写数据

//osThreadId_t g_oledTaskID = NULL;
unsigned char OLED_GRAM[144][8];
unsigned char g_send_data[2] = { 0 };

/**
 * @brief IIC写入1个字节
 * @param id: 对应的I2C组
 * @param device_addr: Oled的设备地址，这里默认是0X78
 * @param send_len: 写入的数据长度 
 */ 
unsigned int IICWrite(unsigned int id, unsigned short device_addr, unsigned int send_len)
{
    int status = 0;

    status = IoTI2cWrite(id, device_addr, g_send_data, send_len);
	if (status != IOT_SUCCESS)
	{
        printf("===== Error: I2C write status = %d! =====\r\n", status);
        return status;
    }
    return IOT_SUCCESS;
}

/**
 * @brief IIC写1字节命令
 * @param IIC_Command: 写入的命令值
 */ 
void IICWriteCommand(unsigned char IIC_Command)
{
    g_send_data[0] = 0x00;
    g_send_data[1] = IIC_Command;

    IICWrite(IOT_I2C_IDX_0, 0x78, 2);
}

/**
 * @brief IIC写1字节数据
 * @param IIC_Command: 写入的数据值
 */ 
void IICWriteData(unsigned char IIC_Data)
{
    g_send_data[0] = 0x40;
    g_send_data[1] = IIC_Data;

    IICWrite(IOT_I2C_IDX_0, 0x78, 2);
}

/**
 * @brief IIC写Oled函数，包括写命令和写数据
 * @param val: 写入的数值
 * @param type: 写入的类型:数据/命令
 */ 
void OledSendByte(unsigned char val, unsigned char type)
{
	if(type == OLED_DATA) 
	{
       IICWriteData(val);
    }
	else 
	{
       IICWriteCommand(val);	
	}
}

/**
 * @brief 设置写入Oled的起始地址
 * @param x: 设置竖起始地址
 * @param y: 设置行起始地址
 */ 
void OledSendBP(unsigned char x,unsigned char y)
{
	OledSendByte(0xb0 + y,OLED_CMD);//设置行起始地址
	OledSendByte(((x & 0xf0) >> 4) | 0x10,OLED_CMD);
	OledSendByte((x & 0x0f),OLED_CMD);
}

/**
 * @brief 开启Oled显示
 */ 
void OledShowON(void)
{
	OledSendByte(0x8D,OLED_CMD);//电荷泵使能
	OledSendByte(0x14,OLED_CMD);//开启电荷泵
	OledSendByte(0xAF,OLED_CMD);//点亮屏幕
}

/**
 * @brief 关闭Oled显示
 */ 
void OledShowOFF(void)
{
	OledSendByte(0x8D,OLED_CMD);//电荷泵使能
	OledSendByte(0x10,OLED_CMD);//关闭电荷泵
	OledSendByte(0xAF,OLED_CMD);//关闭屏幕
}

/**
 * @brief 更新Oled显示的屏
 */ 
void OledRefresh(void)
{
	unsigned char i = 0, n = 0;
	for(i = 0; i < 8; i++)
	{
		OledSendByte(0xb0+i,OLED_CMD); //设置行起始地址
		OledSendByte(0x00,OLED_CMD);   //设置低列起始地址
		OledSendByte(0x10,OLED_CMD);   //设置高列起始地址
		for(n = 0; n < 128; n++)
		{
			OledSendByte(OLED_GRAM[n][i],OLED_DATA);
		}
    }
}

/**
 * @brief 清除Oled屏幕
 */ 
void OledClear(void)
{
	unsigned char  i,n;
	for(i=0;i<8;i++)
	{
	   for(n=0;n<128;n++)
		{
			OLED_GRAM[n][i]=0;//清除所有数据
		}
    }
  	OledRefresh();//更新显示
}

/**
 * @brief Oled画点函数
 * @param x: 画点的竖地址，0~127
 * @param y: 画点的行地址，0~63
 */ 
void OledDrawPoint(unsigned char x,unsigned char y)
{
	unsigned char  i,m,n;
	i = y/8;
	m = y%8;
	n = 1<<m;
	OLED_GRAM[x][i] |= n;
}

/**
 * @brief Oled清除一个点
 * @param x: 点的竖地址，0~127
 * @param y: 点的行地址，0~63
 */ 
void OledClearPoint(unsigned char x,unsigned char y)
{
	unsigned char i = 0, m = 0, n = 0;
	i = y / 8;
	m = y % 8;
	n = 1 << m;
	OLED_GRAM[x][i] = ~OLED_GRAM[x][i];
	OLED_GRAM[x][i] |= n;
	OLED_GRAM[x][i] = ~OLED_GRAM[x][i];
}

/**
 * @brief 在指定位置显示一个字符,包括部分字符(取模方式 逐列式)
 * @param x: 字符的竖地址，0~127
 * @param y: 字符的行地址，0~63
 * @param chr: 显示的字符值
 * @param size1: 字符显示字体:12/16/24
 */ 
void OledShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char size1)
{
	unsigned char i = 0, m = 0;
	unsigned char temp = 0, size2 = 0, chr1 = 0;
	unsigned char y0 = y;
	size2 = (size1 / 8 + ((size1 % 8)? 1: 0)) * (size1 / 2);  //得到字体一个字符对应点阵集所占的字节数
	chr1 = chr - ' ';  //计算偏移后的值
	for(i = 0; i < size2; i++)
	{
		if(size1 == 12)//调用1206字体
        {
			temp = asc2_1206[chr1][i];
		} 
		else if(size1 == 16)//调用1608字体
        {
			temp = asc2_1608[chr1][i];
		} 
		else
		{
			return;
		}

        for(m = 0; m < 8; m++)//写入数据
        {
            if(temp & 0x80)
			{
				OledDrawPoint(x,y);
			}
            else 
			{
				OledClearPoint(x,y);
			}
            temp <<= 1;
            y++;
            if((y - y0) == size1)
            {
                y = y0;
                x++;
                break;
            }
		}
  	}
}

/**
 * @brief 在指定位置显示字符串
 * @param x: 字符的竖地址，0~127
 * @param y: 字符的行地址，0~63
 * @param chr: 显示的字符串
 * @param size1: 字符显示字体:12/16/24
 */ 
void OledShowString(unsigned char x,unsigned char y,char *chr,unsigned char size1)
{
	while((*chr >= ' ') && (*chr <= '~'))//判断是不是非法字符!
	{
		OledShowChar(x,y,*chr,size1);
		x += size1 / 2;
		if(x > 128 - size1)  //换行
		{
			x = 0;
			y += 2;
    	}
		chr++;
  	}
}

/**
 * @brief Oled初始化函数
 */ 
static void OledInit(void)
{
    OledSendByte(0xAE,OLED_CMD);//--turn off oled panel  #
	OledSendByte(0x00,OLED_CMD);//---set low column address #
	OledSendByte(0x10,OLED_CMD);//---set high column address #
	OledSendByte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F) #
	OledSendByte(0x81,OLED_CMD);//--set contrast control register #
	OledSendByte(0xCF,OLED_CMD);// Set SEG Output Current Brightness #
	OledSendByte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常 #
	OledSendByte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常 #
	OledSendByte(0xA6,OLED_CMD);//--set normal display
	OledSendByte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64) #
	OledSendByte(0x3f,OLED_CMD);//--1/64 duty #
	OledSendByte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F) #
	OledSendByte(0x00,OLED_CMD);//-not offset #
	OledSendByte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency #
	OledSendByte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec #
	OledSendByte(0xD9,OLED_CMD);//--set pre-charge period #
	OledSendByte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock #
	OledSendByte(0xDA,OLED_CMD);//--set com pins hardware configuration #
	OledSendByte(0x12,OLED_CMD); // #
	OledSendByte(0xDB,OLED_CMD);//--set vcomh #
	OledSendByte(0x40,OLED_CMD);//Set VCOM Deselect Level #
	OledSendByte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02) #
	OledSendByte(0x02,OLED_CMD);//
	OledSendByte(0x8D,OLED_CMD);//--set Charge Pump enable/disable #
	OledSendByte(0x14,OLED_CMD);//--set(0x10) disable #
	OledSendByte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5) #
	OledSendByte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)  #
	OledSendByte(0xAF,OLED_CMD);// #
	OledClear();
}
/**
 * @brief 
 */
void I2coInit()
{
     //初始化I2C0 配置，速率为400K
	IoTGpioInit(IOT_GPIO_IO_GPIO_13);
	IoTGpioInit(IOT_GPIO_IO_GPIO_14);

    IoTIoSetPull(IOT_GPIO_IO_GPIO_13, IOT_IO_PULL_UP);
    IoTIoSetPull(IOT_GPIO_IO_GPIO_14, IOT_IO_PULL_UP);

	IoTIoSetFunc(IOT_GPIO_IO_GPIO_13, IOT_IO_FUNC_GPIO_13_I2C0_SDA);
	IoTIoSetFunc(IOT_GPIO_IO_GPIO_14, IOT_IO_FUNC_GPIO_14_I2C0_SCL);

    IoTI2cInit(IOT_I2C_IDX_0, 400*1000); 

}
